﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using Nop.Services.Configuration;
using Nop.Services.Payments;
using Nop.Core.Plugins;
using System.Web.Routing;
using Nop.Plugin.Payments.Cielo.Controllers;
using System.Xml;
using Nop.Services.Localization;
using Nop.Services.Tax;
using Nop.Services.Catalog;
using Nop.Services.Directory;
using Nop.Services.Customers;
using Nop.Core;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain;

namespace Nop.Plugin.Payments.Cielo
{
    public class PaymentCieloProcessor : BasePlugin, IPaymentMethod
    {
        #region Fields
        public string autorizar;
        public string capturar;

        public string dadosEcNumero { get; set; }
        public string dadosEcChave { get; set; }

        public string dadosPortadorNumero { get; set; }
        public string dadosPortadorVal { get; set; }
        public string dadosPortadorInd { get; set; }
        public string dadosPortadorCodSeg { get; set; }
        public string dadosPortadorNome { get; set; }

        public string dadosPedidoNumero { get; set; }
        public string dadosPedidoValor { get; set; }
        public string dadosPedidoData { get; set; }
        public string dadosPedidoDescricao { get; set; }
        public string formaPagamentoBandeira { get; set; }
        public string formaPagamentoProduto { get; set; }
        public string formaPagamentoParcelas { get; set; }
        public string dadosPedidoMoeda = "986";
        public string dadosPedidoIdioma = "PT";

        public string tid;
        public string pan;
        public string status;
        public string urlAutenticacao;
        private const string ENCODING = "ISO-8859-1";
        private const string VERSAO = "1.1.0";

        private readonly PaymentCieloSettings _paymentCieloSettigns;
        private readonly ISettingService _settingService;
        private readonly ITaxService _taxService;
        private readonly IPriceCalculationService _priceCalculationService;
        private readonly ICurrencyService _currencyService;
        private readonly ICustomerService _customerService;
        private readonly CurrencySettings _currencySettings;
        private readonly IWebHelper _webHelper;
        private readonly StoreInformationSettings _storeInformationSettings;
        #endregion

        #region Constructor
        public PaymentCieloProcessor(PaymentCieloSettings paymentCieloSettings, ISettingService settingService,
            ITaxService taxService, IPriceCalculationService priceCalculationService,
            ICurrencyService currencyService, ICustomerService customerService,
            CurrencySettings currencySettings, IWebHelper webHelper,
            StoreInformationSettings storeInformationSettings)
        {
            this._paymentCieloSettigns = paymentCieloSettings;
            this._settingService = settingService;
            this._taxService = taxService;
            this._priceCalculationService = priceCalculationService;
            this._currencyService = currencyService;
            this._customerService = customerService;
            this._currencySettings = currencySettings;
            this._webHelper = webHelper;
            this._storeInformationSettings = storeInformationSettings;
        }
        #endregion

        #region Methods

        private string XMLHeader()
        {
            return "<?xml version=\"1.0\" encoding=\"" + ENCODING + "\" ?>";
        }

        private string XMLDadosEc()
        {
            string msg = "<dados-ec>" +
                         "<numero>" +
                         this.dadosEcNumero+
                         "</numero>" +
                         "<chave>" +
                         this.dadosEcChave +
                         "</chave>" +
                         "</dados-ec>";
            return msg;
        }
        private string XMLDadosPortador()
        {
            string msg = "<dados-portador>" +
                        "<numero>" +
                            this.dadosPortadorNumero +
                        "</numero>" +
                        "<validade>" +
                            this.dadosPortadorVal +
                        "</validade>" +
                        "<indicador>" +
                            this.dadosPortadorInd +
                        "</indicador>" +
                        "<codigo-seguranca>" +
                            this.dadosPortadorCodSeg +
                        "</codigo-seguranca>";

            if (this.dadosPortadorNome != null && this.dadosPortadorNome != "")
            {
                msg += "<nome-portador>" +
                            this.dadosPortadorNome +
                        "</nome-portador>";
            }
            msg += "</dados-portador>";

            return msg;
        }
        private string XMLDadosCartao()
        {
            string msg = "<dados-cartao>" +
                        "<numero>" +
                             this.dadosPortadorNumero +
                        "</numero>" +
                        "<validade>" +
                             this.dadosPortadorVal +
                        "</validade>" +
                        "<indicador>" +
                             this.dadosPortadorInd +
                        "</indicador>" +
                        "<codigo-seguranca>" +
                             this.dadosPortadorCodSeg +
                        "</codigo-seguranca>";

            // Verifica se Nome do Portador foi informado				
            if (this.dadosPortadorNome != null && this.dadosPortadorNome != "")
            {
                msg += "   <nome-portador>" +
                             this.dadosPortadorNome +
                        "</nome-portador>";
            }
            msg += "</dados-cartao>";

            return msg;
        }
        private string XMLDadosPedido()
        {
            this.dadosPedidoData = DateTime.Now.ToString("yyyy-MM-dd") + "T" + DateTime.Now.ToString("hh:mm:ss");
            string msg = "<dados-pedido>" +
                        "<numero>" +
                         this.dadosPedidoNumero +
                        "</numero>" +
                        "<valor>" +
                             this.dadosPedidoValor +
                        "</valor>" +
                        "<moeda>" +
                             this.dadosPedidoMoeda +
                        "</moeda>" +
                        "<data-hora>" +
                            this.dadosPedidoData +
                        "</data-hora>";
            if (this.dadosPedidoDescricao != null && this.dadosPedidoDescricao != "")
            {
                msg += "<descricao>" +
                     this.dadosPedidoDescricao +
                    "</descricao>";
            }
            msg += "<idioma>" +
                        this.dadosPedidoIdioma +
                    "</idioma>" +
                    "</dados-pedido>";

            return msg;
        }
        private string XMLFormaPagamento()
        {
            string msg = "<forma-pagamento>" +
                        "<bandeira>" +
                         this.formaPagamentoBandeira +
                        "</bandeira>" +
                        "<produto>" +
                             this.formaPagamentoProduto +
                        "</produto>" +
                        "<parcelas>" +
                             this.formaPagamentoParcelas +
                        "</parcelas>" +
                    "</forma-pagamento>";

            return msg;
        }
        private string XMLUrlRetorno()
        {
            return "<url-retorno>" + this._paymentCieloSettigns.urlRetorno + "</url-retorno>";
        }
        private string XMLAutorizar()
        {
            return "<autorizar>" + this.autorizar + "</autorizar>";
        }
        private string XMLCapturar()
        {
            return "<capturar>" + this.capturar + "</capturar>";
        }
        #endregion
        #region "Methods"
        // Envia Requisição
        public System.Data.DataSet Enviar(string vmPost)
        {
            byte[] byteBuffer = Encoding.UTF8.GetBytes("mensagem=" + vmPost);
            Stream requestStream = null;
            WebResponse response = null;
            StreamReader reader = null;
            
            WebRequest request;
            if (this._paymentCieloSettigns.usarUrlTeste) request = WebRequest.Create(this._paymentCieloSettigns.urlTeste);
            else request = WebRequest.Create(this._paymentCieloSettigns.urlProducao);

            request.Method = WebRequestMethods.Http.Post;
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = byteBuffer.Length;

            requestStream = request.GetRequestStream();
            requestStream.Write(byteBuffer, 0, byteBuffer.Length);
            requestStream.Close();

            response = request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            System.Text.Encoding encoding = System.Text.Encoding.Default;
            reader = new StreamReader(responseStream, encoding);
            Char[] charBuffer = new Char[256];
            int count = reader.Read(charBuffer, 0, charBuffer.Length);

            StringBuilder Dados = new StringBuilder();
            while (count > 0)
            {
                Dados.Append(new String(charBuffer, 0, count));
                count = reader.Read(charBuffer, 0, charBuffer.Length);
            }

            System.Data.DataSet ds = new System.Data.DataSet();
            
            ds.ReadXml(new StringReader(Dados.ToString()), System.Data.XmlReadMode.Auto);
            return ds;
        }
        // Requisições
        public System.Data.DataSet RequisicaoTransacao(bool incluirPortador)
        {
            string msg = this.XMLHeader() + "\n" +
                   "<requisicao-transacao id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao=\"" + VERSAO + "\">" + "\n   "
                        + this.XMLDadosEc() + "\n   ";
            if (incluirPortador == true)
            {
                msg += this.XMLDadosPortador() + "\n   ";
            }
            msg += this.XMLDadosPedido() + "\n   "
                        + this.XMLFormaPagamento() + "\n   "
                        + this.XMLUrlRetorno() + "\n   "
                        + this.XMLAutorizar() + "\n   "
                        + this.XMLCapturar() + "\n";
            msg += "</requisicao-transacao>";
            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoTid()
        {
            string msg = this.XMLHeader() + "\n" +
                   "<requisicao-tid id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao =\"" + VERSAO + "\">" + "\n   "
                        + this.XMLDadosEc() + "\n   "
                        + this.XMLFormaPagamento() + "\n" +
                   "</requisicao-tid>";
            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoAutorizacaoPortador()
        {
            string msg = this.XMLHeader() + "\n" +
                   "<requisicao-autorizacao-portador id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao =\"" + VERSAO + "\">" + "\n"
                        + "<tid>" + this.tid + "</tid>" + "\n   "
                        + this.XMLDadosEc() + "\n   "
                        + this.XMLDadosCartao() + "\n   "
                        + this.XMLDadosPedido() + "\n   "
                        + this.XMLFormaPagamento() + "\n   "
                        + "<capturar-automaticamente>" + this.capturar + "</capturar-automaticamente>" + "\n" +
                   "</requisicao-autorizacao-portador>";

            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoAutorizacaoTid()
        {
            string msg = this.XMLHeader() + "\n" +
                 "<requisicao-autorizacao-tid id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao=\"" + VERSAO + "\">" + "\n  "
                    + "<tid>" + this.tid + "</tid>" + "\n  "
                    + this.XMLDadosEc() + "\n" +
                 "</requisicao-autorizacao-tid>";

            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoCaptura(string PercentualCaptura, string anexo)
        {
            string msg = this.XMLHeader() + "\n" +
                    "<requisicao-captura id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao=\"" + VERSAO + "\">" + "\n   "
                    + "<tid>" + this.tid + "</tid>" + "\n   "
                    + this.XMLDadosEc() + "\n   "
                    + "<valor>" + PercentualCaptura + "</valor>" + "\n";
            if (anexo != null && anexo != "")
            {
                msg += "   <anexo>" + anexo + "</anexo>" + "\n";
            }
            msg += "</requisicao-captura>";

            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoCancelamento()
        {
            string msg = this.XMLHeader() + "\n" +
                      "<requisicao-cancelamento id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao=\"" + VERSAO + "\">" + "\n   "
                    + "<tid>" + this.tid + "</tid>" + "\n   "
                    + this.XMLDadosEc() + "\n" +
                   "</requisicao-cancelamento>";

            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        public System.Data.DataSet RequisicaoConsulta()
        {
            string msg = this.XMLHeader() + "\n" +
                   "<requisicao-consulta id=\"" + DateTime.Now.ToString("yyyyMMdd") + DateTime.Now.ToString("hhmmss") + "\" versao=\"" + VERSAO + "\">" + "\n   "
                    + "<tid>" + this.tid + "</tid>" + "\n   "
                    + this.XMLDadosEc() + "\n" +
                   "</requisicao-consulta>";

            System.Data.DataSet objResposta = this.Enviar(msg);
            return objResposta;
        }
        // Transforma em/lê string
        public string ToString()
        {
            string msg = this.XMLHeader() +
                   "<objeto-pedido>" +
                     "<tid>" + this.tid + "</tid>"
                    + "<status>" + this.status + "</status>"
                    + this.XMLDadosEc()
                    + this.XMLDadosPedido()
                    + this.XMLFormaPagamento() +
                   "</objeto-pedido>";

            return msg;
        }
        // Traduz cógigo do Status
        public string getStatus()
        {
            string status;
            switch (this.status)
            {
                case "0": status = "Criada";
                    break;
                case "1": status = "Em andamento";
                    break;
                case "2": status = "Autenticada";
                    break;
                case "3": status = "Não autenticada";
                    break;
                case "4": status = "Autorizada";
                    break;
                case "5": status = "Não autorizada";
                    break;
                case "6": status = "Capturada";
                    break;
                case "8": status = "Não capturada";
                    break;
                case "9": status = "Cancelada";
                    break;
                case "10": status = "Em autenticação";
                    break;
                default: status = "n/a";
                    break;
            }

            return status;
        }
        #endregion

        public override void Install()
        {


            var settings = new PaymentCieloSettings()
            {
                usarUrlTeste = true,
            };
            _settingService.SaveSetting(settings);

            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlTeste", "Url de teste");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlProducao", "Url de produção");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UsarUrlTeste", "Ativar modo de testes");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlRetorno", "Url de Retorno");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.Loja", "Loja");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.LojaChave", "Loja Chave");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.Cielo", "Cielo");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.CieloChave", "Cielo Chave");


            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlTeste.Hint", "Url de testes: fornecida pela Cielo. Esta Url permite que você teste a implantação do plugin. Para usar URL de testes, você deve ativar a opção: 'Ativar modo de testes'.");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlProducao.Hint", "Url de produção: fornecida pela Cielo. Esta Url envia dados para o ambiente de produção da Cielo. Não é recomendado o uso desta URL para testes.");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UsarUrlTeste.Hint", "Ativar modo de testes: ativa o uso da URL de testes. Marque esta opção para testar integração.");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.UrlRetorno.Hint", "Url de Retorno: Url do seu site que vai receber o retorno da operadora Cielo. Este retorno contém o status do processamento das transações enviadas.");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.Loja.Hint", "Loja");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.LojaChave.Hint", "Loja Chave");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.Cielo.Hint", "Cielo");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payment.Cielo.CieloChave.Hint", "Cielo Chave");
            base.Install();
        }

        public override void Uninstall()
        {
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlTeste");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlProducao");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UsarUrlTeste");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlRetorno");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.Loja");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.LojaChave");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.Cielo");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.CieloChave");

            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlTeste.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlProducao.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UsarUrlTeste.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.UrlRetorno.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.Loja.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.LojaChave.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.Cielo.Hint");
            this.DeletePluginLocaleResource("Plugins.Payment.Cielo.CieloChave.Hint");

            base.Uninstall();
        }

        public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public decimal GetAdditionalHandlingFee()
        {
            return 0;
        }

        public CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest)
        {
            throw new NotImplementedException();
        }

        public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest)
        {
            throw new NotImplementedException();
        }

        public bool CanRePostProcessPayment(Core.Domain.Orders.Order order)
        {
            throw new NotImplementedException();
        }

        public void GetConfigurationRoute(out string actionName, out string controllerName, out System.Web.Routing.RouteValueDictionary routeValues)
        {
            actionName = "Configure";
            controllerName = "PaymentCielo";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Nop.Plugin.Payments.Cielo.Controllers" }, { "area", null } };
        }

        public void GetPaymentInfoRoute(out string actionName, out string controllerName, out System.Web.Routing.RouteValueDictionary routeValues)
        {
            actionName = "PaymentInfo";
            controllerName = "PaymentCielo";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Nop.Plugin.Payments.Cielo.Controllers" }, { "area", null } };
        }

        public Type GetControllerType()
        {
            return typeof(PaymentCieloController);
        }

        public bool SupportCapture
        {
            get
            {
                return true;
            }
        }
        /// <summary>
        /// Gets a value indicating whether partial refund is supported
        /// </summary>
        public bool SupportPartiallyRefund
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets a value indicating whether refund is supported
        /// </summary>
        public bool SupportRefund
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether void is supported
        /// </summary>
        public bool SupportVoid
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets a recurring payment type of payment method
        /// </summary>
        public RecurringPaymentType RecurringPaymentType
        {
            get
            {
                return RecurringPaymentType.Automatic;
            }
        }

        /// <summary>
        /// Gets a payment method type
        /// </summary>
        public PaymentMethodType PaymentMethodType
        {
            get
            {
                return PaymentMethodType.Standard;
            }
        }
    }
}
